package cn.iocoder.yudao.module.asasc.dal.redis;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.module.asasc.common.ASATokenUtils;
import cn.iocoder.yudao.module.asasc.dal.dataobject.campaign.AsaAppConfigDO;
import cn.iocoder.yudao.module.asasc.dal.dataobject.oauth.ClientSecretDO;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;

import static cn.iocoder.yudao.module.asasc.dal.redis.RedisKeyConstants.ASA_TOKEN;
import static cn.iocoder.yudao.module.asasc.dal.redis.RedisKeyConstants.CLIENT_SECRET;

/**
 * ASA 缓存服务
 * <p>
 * {@link ClientSecretDO} 的 RedisDAO
 */
@Repository
public class AsaTokenRedisDAO {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private static String formatSecretKey(Long orgId) {
        return String.format(CLIENT_SECRET, orgId);
    }

    private static String formatTokenKey(Long orgId) {
        return String.format(ASA_TOKEN, orgId);
    }

    /**
     * 创建并缓存 clientSecret 有效期 180天
     *
     * @param appConfigDO
     * @return
     */
    public ClientSecretDO getClientSecret(AsaAppConfigDO appConfigDO) {
        ClientSecretDO clientSecretDO;
        String redisKey = formatSecretKey(appConfigDO.getOrgId());

        // 缓存不存在，重新生成，设置过期时间 180天
        if (Boolean.FALSE.equals(stringRedisTemplate.hasKey(redisKey))) {
            String clientSecret = ASATokenUtils.createClientSecret(appConfigDO);
            clientSecretDO = new ClientSecretDO();
            clientSecretDO.setOrgId(appConfigDO.getOrgId());
            //设置过期时间为 180 天以后
            LocalDateTime expiresTime = LocalDateTime.now().plusDays(180);
            clientSecretDO.setExpiresTime(expiresTime);
            clientSecretDO.setClientSecret(clientSecret);

            setClientSecret(clientSecretDO);
        } else {
            clientSecretDO = JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), ClientSecretDO.class);
            // 如果过期时间只有 2 天了，重新生成
            assert clientSecretDO != null;
            if (LocalDateTime.now().isAfter(clientSecretDO.getExpiresTime().minusDays(2))) {
                String clientSecret = ASATokenUtils.createClientSecret(appConfigDO);
                clientSecretDO.setClientSecret(clientSecret);
                clientSecretDO.setExpiresTime(LocalDateTime.now().plusDays(180));
                setClientSecret(clientSecretDO);
            }
        }
        return clientSecretDO;
    }

    public void setClientSecret(ClientSecretDO clientSecretDO) {
        String redisKey = formatSecretKey(clientSecretDO.getOrgId());
        long time = LocalDateTimeUtil.between(LocalDateTime.now(), clientSecretDO.getExpiresTime(), ChronoUnit.SECONDS);
        if (time > 0) {
            stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(clientSecretDO), time, TimeUnit.SECONDS);
        }
    }

    public void delete(Long orgId) {
        String redisKey = formatSecretKey(orgId);
        stringRedisTemplate.delete(redisKey);
    }

    /**
     * 创建并缓存 ASA Token，有效期一个小时
     *
     * @param appConfigDO
     * @return
     */
    public String getToken(AsaAppConfigDO appConfigDO) {
        String redisKey = formatTokenKey(appConfigDO.getOrgId());
        if (Boolean.FALSE.equals(stringRedisTemplate.hasKey(redisKey))) {
            ClientSecretDO clientSecretDO = getClientSecret(appConfigDO);
            if (clientSecretDO == null) {
                return null;
            }
            String asaToken = ASATokenUtils.getAsaToken(appConfigDO.getClientId(), clientSecretDO.getClientSecret());
            assert asaToken != null;
            stringRedisTemplate.opsForValue().set(redisKey, asaToken, 1, TimeUnit.HOURS);
        }
        return stringRedisTemplate.opsForValue().get(redisKey);
    }
}